#ifndef URL_DOWNLOAD_TOOLS_H
#define URL_DOWNLOAD_TOOLS_H

#pragma once

#include <Urlmon.h>
#include "lib.h"

#ifdef UNICODE
    #define _T_DEBUGMSG(x)  UDEBUGMSG(x)
#else
    #define _T_DEBUGMSG(x)  DEBUGMSG(x)
#endif
#define _T_LOG_OR_TRACE_MSG1(a)                     
#define _T_LOG_OR_TRACE_MSG2(a,b)                   
#define _T_LOG_OR_TRACE_MSG3(a,b,c)                 
#define _T_LOG_OR_TRACE_MSG4(a,b,c,d)               
#define _T_LOG_OR_TRACE_MSG5(a,b,c,d,e)             
#define _T_LOG_OR_TRACE_MSG6(a,b,c,d,e,f)           
#define _T_LOG_OR_TRACE_MSG7(a,b,c,d,e,f,g)         
#define _T_LOG_OR_TRACE_MSG8(a,b,c,d,e,f,g,h)  
#define _T_LOG_OR_TRACE_MSG9(a,b,c,d,e,f,g,h,i)     

#define PACKAGELIST_INI_MACRO      _T("package_list.ini")


class ZipFile;
class PathName;
class URLDownloadCallback;

class URLDownloadProgressEventHandler
{
public:
    virtual bool isCancelled() const = 0;
    virtual void UpdateProgress(ULONG ulNewAmountDownloaded   /* new bytes downloaded since last event */, 
                                ULONG ulTotalAmountDownloaded /* total bytes downloaded thus far */, 
                                ULONG ulTotalFileSize         /* total bytes in file being downloaded */  ) const = 0;
};

class URLDownloadTools
{
public:
    enum LogLevel
    {
        LOGLEVEL_GET_FROM_FILE = -1,        // log level is determined from [DownloadTrace] LogLevel setting in DownloadTrace.ini
        LOGLEVEL_OFF = 0,                   // all logging is OFF
        LOGLEVEL_DEBUG_TRACE = 1,           // only TRACE debug message (do not log to file)
        LOGLEVEL_DEBUG_LOG = 2,             // log debug message
        LOGLEVEL_PROGRESS_LOG = 3,          // log debug and progress messages
        LOGLEVEL_BINDSTATUSCALLBACK_LOG = 4 // log debug. progress, and bind status callback messages
    };

    enum DownloadError
    {
        DWNLDERR_NONE = 0,
        DWNLDERR_DOWNLOAD_CANCELLED,
        DWNLDERR_DOWN_FOR_MAINT,
        DWNLDERR_FILE_NOT_FOUND,
        DWNLDERR_COMMUNICATION_ERROR,
        DWNLDERR_OPEN_FAILED,
        DWNLDERR_WRITE_FAILED,
        DWNLDERR_CRC_VERIFICATION_FAILED,
        DWNLDERR_UNEXPECTED
    };
    static DownloadError DownloadPackage(LPCTSTR szBaseURL, 
                                         LPCTSTR szURL, 
                                         LPCTSTR szFileName, 
                                         uint32 crcVerify = 0 /* NOTE: 0 means skip CRC verification */, 
                                         const URLDownloadProgressEventHandler* pProgressHandler = NULL, 
                                         bool bAutoUnZip = true);
    static DownloadError DownloadFile(LPCTSTR szBaseURL, 
                                      LPCTSTR szURL, 
                                      LPCTSTR szFileName, 
                                      uint32 crcVerify = 0 /* NOTE: 0 means skip CRC verification */, 
                                      const URLDownloadProgressEventHandler* pProgressHandler = NULL, 
                                      bool bAutoUnZip = true);

    static bool          ComputeFileCRC(LPCTSTR szFileName, uint32& crc32);
    static bool          IsPackageListIniUpToDate(const String& strPackageListINI, 
                                                  bool bTraceAllErrors = false);
    static int32         GetPackageSectionNumber(const String& strPackageListINI, 
                                                 const String& strPackageName, 
                                                 bool bTraceAllErrors = false);
    static String        GetPackageVersion(const String& strPackageListINI, 
                                           const String& strPackageName, 
                                           bool bTraceAllErrors = false);
    static String        GetRemoteFolderName(const String& strPackageListINI, 
                                             const String& strPackageName, 
                                             bool bTraceAllErrors = false);
    static uint32        GetExpectedPackageSize(const String& strPackageListINI, 
                                                const String& strPackageName, 
                                                bool bGetCompressedSize = true, 
                                                bool bTraceAllErrors = false);
    static uint32        GetExpectedPackageCRC(const String& strPackageListINI, 
                                               const String& strPackageName, 
                                               bool bTraceAllErrors = false);
    static DownloadError VerifyPackageContents(const String& strPackageName, 
                                               const String& strPackagePath, 
                                               bool bTraceErrorsAndProgress = false);
    static DownloadError UnZipPackage(LPCTSTR szZipFileName, LPCTSTR szUnZipPath);
    static DownloadError UnZipFile(LPCTSTR szZipFileName, LPCTSTR szUnZipPath);

private:
    // cannot create, copy, or assign URLDownloadTools (static helpers only) 
    URLDownloadTools();
    URLDownloadTools(const URLDownloadTools&);
    URLDownloadTools& operator=(const URLDownloadTools&);
};

typedef URLDownloadTools::DownloadError DWNLDERR;


#endif
